在系統開發與架構設計中,「軟編碼 (Soft-coding)」 是確保系統長期具備彈性與可維護性的核心原則。在 Build on Google AI 賽道的「NGO 房間與資源預約管理系統」中,我們包含許多商業與營運規則(如開放時段、節數時長、預約天數上限、24 小時違規條款與租用費用)。
今天我們將系統最新的 SRD (Software Requirements Description) 規格(包含四大核心模組 A/B/C/D 與 Data Schema,並採用最新的 Gemini 3.6 Flash 模型)進行全面整合,並在 Google Apps Script 中建立全系統的心臟——Config.gs 設定檔。未來管理員若需要微調營運政策或更換 API 金鑰,只需修改此設定檔,無須動到任何核心業務邏輯程式碼。
為了讓後續開發(包含使用 Google AI 工具協同編碼)具備清晰且結構化的準則,以下為系統完整的 SRD 規格說明:
gemini-3.6-flash) via Google AI StudioUser_Roles (職工與權限表)| 欄位 (Column) | 型態 | 說明 / 允許值 |
|---|---|---|
email |
String | 職工 Email (PK) |
role |
String | ADMIN / USER |
department |
String | 隸屬部門 |
status |
String | PENDING_APPROVAL / ACTIVE / SUSPENDED |
created_at |
DateTime | 帳戶建立時間 |
Bookings (預約紀錄表)| 欄位 (Column) | 型態 | 說明 / 允許值 |
|---|---|---|
booking_id |
String | 預約唯一編號 (PK, e.g., BK_1712345678) |
room_id |
String | 房間代號 (A1, A2, B1, B2, TALK_ROOM) |
user_email |
String | 預約職工 Email |
start_time |
DateTime | 預約開始時間 |
end_time |
DateTime | 預約結束時間 |
status |
String | APPROVED / CANCELLED_VALID / LATE_CANCELLED / CANCELLED_WAIVED |
check_in_status |
String | NOT_CHECKED_IN / CHECKED_IN |
purpose |
String | 預約用途說明 |
created_at |
DateTime | 建立時間 |
admin_note |
String | 管理員酌情備註 |
sendVerificationCode(email):產生 6 位數 OTP 存入 Cache (10分鐘有效),並透過 Gmail 發送驗證信。verifyOTPAndRegister(email, code, department):驗證 OTP,成功後於 User_Roles 新增 PENDING_APPROVAL 紀錄,並觸發 Telegram 通知管理員。此狀態下阻擋使用者登入與預約。approveUserAccount(adminEmail, targetEmail):管理員審核通過後將狀態更新為 ACTIVE,並寄送帳戶開通通知信。updateUserStatus(adminEmail, targetEmail, newStatus):管理員可隨時將帳戶轉為 SUSPENDED(暫停)或刪除該欄紀錄 REMOVED(徹底移除)。getAvailableSlots(date, roomId):根據 Config 設定(08:00 - 22:00,以 30 分鐘為一節),回傳該房間當日的所有可用時段。submitNewBooking(userEmail, roomId, startTime, endTime, purpose):MAX_BOOKING_ADVANCE_DAYS (90天)。StartA < EndB AND EndA > StartB)。Bookings 表,狀態設為 APPROVED,並呼叫 Telegram Bot API 發送新預約推播通知至管理員頻道。cancelBooking(userEmail, bookingId, reason):(startTime - now) 的小時差。CANCELLED_VALID,不予計費。LATE_CANCELLED,視為預約不使用,照樣納入計費。callGeminiApi(prompt):封裝最新的 Google Gemini API (gemini-3.6-flash),用於分析預約數據與產生個人化對帳評語。applyAdminDiscretion(bookingId, adminEmail, note):管理員對特殊情況點擊豁免,將狀態設為 CANCELLED_WAIVED 並填寫備註,於月結單中剔除計費。generateMonthlyReportAndSendStatements():LATE_CANCELLED 次數與總應計費用(每節 HKD $50)。Config.gs) 程式碼實作請在 Google Apps Script 專案中新增名為 Config.gs 的檔案,並寫入以下程式碼:
/**
* ==============================================================================
* 系統全局設定檔 (Config.gs)
* 專案:NGO 房間與資源預約管理系統 (Build on Google AI Track)
* 說明:集中管理 SRD 所定義之營運規則參數、最新 Google AI (Gemini 3.6 Flash) 與 Telegram Bot API 金鑰。
* ==============================================================================
*/
const SYSTEM_CONFIG = {
// ----------------------------------------------------------------------------
// 1. 營運規則與時間參數 (Operations Settings)
// ----------------------------------------------------------------------------
/** 每日開始營業時間 (24小時制,格式 HH:mm) */
WORK_START_TIME: "08:00",
/** 每日結束營業時間 (24小時制,格式 HH:mm) */
WORK_END_TIME: "22:00",
/** 每節預約時長(單位:分鐘) */
SLOT_DURATION_MINUTES: 30,
/** 開放預訂的最長天數(例如:可預訂未來 90 天內的時段) */
MAX_BOOKING_ADVANCE_DAYS: 90,
/** 預約取消後,改訂新日期的有效期限(單位:天) */
MAX_RESCHEDULE_DAYS: 60,
/** 每節(30 分鐘)標準租用費用(單位:HKD) */
FEE_PER_SLOT: 50,
/** 免費/違規取消臨界線(單位:小時,少於 24 小時取消視為預約不使用照樣計費) */
LATE_CANCELLATION_THRESHOLD_HOURS: 24,
// ----------------------------------------------------------------------------
// 2. Google AI (Gemini) 與外部 API 金鑰設定 (API Keys & Integrations)
// ----------------------------------------------------------------------------
/**
* Google Gemini 模型名稱 (指定使用最新的 gemini-3.6-flash)
*/
GEMINI_MODEL: "gemini-3.6-flash",
/**
* Google Gemini API Key (Build on Google AI 賽道核心)
* 優先從 Script Properties 讀取,確保金鑰不寫死在程式碼中
*/
GEMINI_API_KEY: PropertiesService.getScriptProperties().getProperty("GEMINI_API_KEY") || "YOUR_GEMINI_API_KEY_HERE",
/**
* Telegram Bot API Key (用於發送即時審批、預約異動與月結通知)
*/
TELEGRAM_BOT_TOKEN: PropertiesService.getScriptProperties().getProperty("TELEGRAM_BOT_TOKEN") || "YOUR_TELEGRAM_BOT_TOKEN_HERE",
/**
* Telegram 管理員通知頻道/群組 Chat ID
*/
TELEGRAM_ADMIN_CHAT_ID: PropertiesService.getScriptProperties().getProperty("TELEGRAM_ADMIN_CHAT_ID") || "YOUR_ADMIN_CHAT_ID_HERE",
/**
* Telegram API 基礎 URL 端點
*/
TELEGRAM_API_BASE_URL: "https://api.telegram.org/bot",
/**
* Google API Key (用於 Google Calendar / Map 等擴充服務)
*/
GOOGLE_API_KEY: PropertiesService.getScriptProperties().getProperty("GOOGLE_API_KEY") || "YOUR_GOOGLE_API_KEY_HERE",
/**
* 主資料庫 Google Sheet ID
*/
SPREADSHEET_ID: PropertiesService.getScriptProperties().getProperty("SPREADSHEET_ID") || "YOUR_SPREADSHEET_ID_HERE",
/**
* 系統管理員通知接收 Email
*/
ADMIN_EMAIL: "admin@ngo.org"
};
/**
* 取得全局設定物件的封裝函式
* @returns {Object} 系統設定物件
*/
function getConfig() {
return SYSTEM_CONFIG;
}
/**
* 發送 Telegram Bot 訊息輔助函式
* @param {string} text - 要發送的訊息內容 (支援 HTML / Markdown)
* @param {string} [chatId] - 目標 Chat ID,若未填則預設發送至管理員頻道
* @returns {boolean} 是否發送成功
*/
function sendTelegramNotification(text, chatId) {
const config = getConfig();
const targetChatId = chatId || config.TELEGRAM_ADMIN_CHAT_ID;
if (!config.TELEGRAM_BOT_TOKEN || config.TELEGRAM_BOT_TOKEN.includes("YOUR_")) {
Logger.log("⚠️ Telegram Bot Token 未設定,跳過 Telegram 通知發送。");
return false;
}
const url = `${config.TELEGRAM_API_BASE_URL}${config.TELEGRAM_BOT_TOKEN}/sendMessage`;
const payload = {
chat_id: targetChatId,
text: text,
parse_mode: "HTML"
};
const options = {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
const response = UrlFetchApp.fetch(url, options);
const result = JSON.parse(response.getContentText());
if (result.ok) {
Logger.log("✅ Telegram 通知發送成功。");
return true;
} else {
Logger.log(`❌ Telegram 通知發送失敗: ${result.description}`);
return false;
}
} catch (error) {
Logger.log(`❌ 呼叫 Telegram API 發生例外錯誤: ${error.toString()}`);
return false;
}
}
/**
* 檢查系統關鍵設定是否已妥善配置
* @returns {Boolean} 設定是否完整
*/
function validateConfig() {
const config = getConfig();
const requiredKeys = ["GEMINI_API_KEY", "TELEGRAM_BOT_TOKEN", "TELEGRAM_ADMIN_CHAT_ID", "SPREADSHEET_ID"];
for (const key of requiredKeys) {
if (!config[key] || config[key].includes("YOUR_")) {
Logger.log(`⚠️ 警告:設定項目 [${key}] 尚未配置正確的值!`);
return false;
}
}
Logger.log("✅ 系統設定檔驗證成功,所有必要參數、Google AI (Gemini 3.6 Flash) 及 Telegram API 金鑰皆已配置。");
return true;
}
以下為 Config.gs 各項參數與 SRD 商業邏輯的映射關係:
| 設定參數 (Key) | SRD 預設值 | 營運邏輯說明 |
|---|---|---|
WORK_START_TIME |
"08:00" |
前端預約日曆每日最早可選擇的時間點。 |
WORK_END_TIME |
"22:00" |
前端預約日曆每日最晚可預約的時間點。 |
SLOT_DURATION_MINUTES |
30 |
系統計算時段的最小單位(30 分鐘為一節)。 |
MAX_BOOKING_ADVANCE_DAYS |
90 |
限制職工最多可預訂未來 90 天內 的房間。 |
MAX_RESCHEDULE_DAYS |
60 |
預約取消後,紀錄保留 60 天內 可重新指派新日期。 |
FEE_PER_SLOT |
50 |
月結單計算費用時,每節(30 分鐘)對應的金額(HKD $50)。 |
LATE_CANCELLATION_THRESHOLD_HOURS |
24 |
臨界線設定,少於 24 小時取消標記為 LATE_CANCELLED 照樣計費。 |
GEMINI_MODEL |
"gemini-3.6-flash" |
指定最新的 Gemini 3.6 Flash 模型,提供更高品質且更低延遲的文字分析能力。 |
GEMINI_API_KEY |
String | Build on Google AI 核心金鑰,用於呼叫 Gemini API 進行預約用途審查與月結對帳摘要生成。 |
TELEGRAM_BOT_TOKEN |
String | Telegram 機器人 Token,用於觸發帳戶審批、預約成功、取消通知與管理員推播。 |
TELEGRAM_ADMIN_CHAT_ID |
String | Telegram 管理群組 Chat ID,用於接收管理員專屬即時提醒與審批訊息。 |
今天將 Google AI 模型版本及 Telegram Bot API 設定,並全面完成 SRD (系統需求說明書) 的整合(模組 A/B/C/D 與 Data Schema)。
明天繼續……